Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | /** * API route for reviewing and correcting parsed worksheet results * * PATCH /api/curriculum/[playerId]/attachments/[attachmentId]/review * - Submit user corrections to parsed problems * - Updates the parsing result with corrections */ import { NextResponse } from 'next/server' import { eq } from 'drizzle-orm' import { z } from 'zod' import { db } from '@/db' import { practiceAttachments, type ParsingStatus } from '@/db/schema/practice-attachments' import { withAuth } from '@/lib/auth/withAuth' import { canPerformAction } from '@/lib/classroom' import { getUserId } from '@/lib/viewer' import { applyCorrections, computeParsingStats, ProblemCorrectionSchema, } from '@/lib/worksheet-parsing' /** * Request body schema for corrections */ const ReviewRequestSchema = z.object({ corrections: z.array(ProblemCorrectionSchema).min(1), markAsReviewed: z.boolean().default(false), }) /** * PATCH - Submit corrections to parsed problems */ export const PATCH = withAuth(async (request, { params }) => { try { const { playerId, attachmentId } = (await params) as { playerId: string; attachmentId: string } if (!playerId || !attachmentId) { return NextResponse.json({ error: 'Player ID and Attachment ID required' }, { status: 400 }) } // Authorization check const userId = await getUserId() const canReview = await canPerformAction(userId, playerId, 'start-session') if (!canReview) { return NextResponse.json({ error: 'Not authorized' }, { status: 403 }) } // Parse request body const body = await request.json() const parseResult = ReviewRequestSchema.safeParse(body) if (!parseResult.success) { return NextResponse.json( { error: 'Invalid request body', details: parseResult.error.issues, }, { status: 400 } ) } const { corrections, markAsReviewed } = parseResult.data // Get attachment record const attachment = await db .select() .from(practiceAttachments) .where(eq(practiceAttachments.id, attachmentId)) .get() if (!attachment) { return NextResponse.json({ error: 'Attachment not found' }, { status: 404 }) } if (attachment.playerId !== playerId) { return NextResponse.json({ error: 'Attachment not found' }, { status: 404 }) } // Check if we have parsing results to correct if (!attachment.rawParsingResult) { return NextResponse.json( { error: 'No parsing results to correct. Parse the worksheet first.', }, { status: 400 } ) } // Apply corrections to approved result (if exists) or raw result // This ensures corrections are cumulative const baseResult = attachment.approvedResult ?? attachment.rawParsingResult const correctedResult = applyCorrections( baseResult, corrections.map((c) => ({ problemNumber: c.problemNumber, correctedTerms: c.correctedTerms ?? undefined, correctedStudentAnswer: c.correctedStudentAnswer ?? undefined, shouldExclude: c.shouldExclude, shouldRestore: c.shouldRestore, })) ) // Compute new stats const stats = computeParsingStats(correctedResult) // Determine new status let newStatus: ParsingStatus = attachment.parsingStatus ?? 'needs_review' if (markAsReviewed) { // If user explicitly marks as reviewed, set to approved newStatus = 'approved' } else if (!correctedResult.needsReview) { // If all problems now have high confidence, auto-approve newStatus = 'approved' } else { // Still needs review newStatus = 'needs_review' } // Update database - store corrected result as approved result await db .update(practiceAttachments) .set({ parsingStatus: newStatus, approvedResult: correctedResult, confidenceScore: correctedResult.overallConfidence, needsReview: correctedResult.needsReview, }) .where(eq(practiceAttachments.id, attachmentId)) return NextResponse.json({ success: true, status: newStatus, result: correctedResult, stats, correctionsApplied: corrections.length, }) } catch (error) { console.error('Error applying corrections:', error) return NextResponse.json({ error: 'Failed to apply corrections' }, { status: 500 }) } }) |